home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 076-100 / 084 / audiotools / audiotools.c next >
C/C++ Source or Header  |  1995-03-13  |  16KB  |  627 lines

  1. /* audiotools.c */
  2.  
  3. #define DEBUG 1
  4.  
  5. #include "exec/types.h"
  6. #include "exec/memory.h"
  7. #include "devices/audio.h"
  8. #include "ram:audiotools.h"
  9. #include "ram:globals.c"
  10. extern APTR AllocMem();
  11. extern struct Message *GetMsg();
  12.  
  13. main()
  14. {
  15.     LONG i, channel, error;
  16.  
  17.     InitAudio();
  18.  
  19.     for(i=0; i<4; i++) 
  20.     {    channel = GetChannel(-1);
  21.         if(channel == -1)  finishup("cannot get a channel!");
  22.  
  23.         /* At this point, must save globals from gotkey, gotunit */
  24.         key[i] = gotkey;    /* save allocation key */
  25.         unit[i] = gotunit;    /* save unit value     */
  26.  
  27.         error = StopChannel(channel);
  28.         if(error) 
  29.         {  printf("error in stopping channel = %ld\n",error);
  30.            finishup("StopChannel did not work as expected");
  31.         }
  32.     }
  33.     /*  (channel, note, waveform, vol, duration, priority,message) */
  34.  
  35.     for(i=0; i<95; i++)
  36.     {
  37.         PlayNote(0, i, w1, 32, 250, 0, 0); /* all notes, 1/4 sec. */
  38.     }
  39.     error = StartChannel(0);
  40.     Delay(800);    /* let most of them play... this waits 16 seconds */
  41.  
  42.     for(i=1; i<4; i++)
  43.     {    error = StartChannel(i);
  44.         if(error)  printf("error starting channel = %ld\n",error);
  45.     }
  46.     PlayNote(0, 23, w1, 32, 2000, 0, 0);
  47.     PlayNote(1, 27, w2, 32, 2300, 0, 0);
  48.     PlayNote(2, 30, w3, 32, 2600, 0, 0);
  49.     PlayNote(3, 35, w1, 32, 2900, 0, 0);
  50.  
  51.     FinishAudio();
  52.     return(0);
  53. }            /* end of main() */
  54.  
  55. InitAudio()
  56. {
  57.        int error,i;
  58.  
  59.     /* Declare all message blocks available */
  60.        for(i=0; i<AUDBUFFERS; i++)  {    inuse[i] = NO;    }
  61.  
  62.     /* Open device but don't allocate channels      */
  63.     openIOB.ioa_Length = 0;    /* (no allocation table) */
  64.  
  65.     error = OpenDevice("audio.device",0,&openIOB,0);
  66.        if(error) finishup ("audio device won't open!");
  67.  
  68.        /* Get the device address for later use */
  69.     device = openIOB.ioa_Request.io_Device;
  70.     
  71.     /* Create ports for replies from each channel as well as
  72.      * one port to be used for the control and synchonous functions */
  73.     for(i=0; i<4; i++) 
  74.     {    auReplyPort = CreatePort(0,0);
  75.         replyPort[i] = auReplyPort;
  76.         if(auReplyPort == 0) finishup("cannot create a port!");
  77.         chipaudio[i] = 0;  /* have not yet created the waves */
  78.         datalength[i] = 1; /* used for custom sound samples  */
  79.     }
  80.     controlPort = CreatePort(0,0);
  81.     if(controlPort == 0) finishup("can't create control port");
  82.     error = MakeWaves();
  83.     if(error == -1)  finishup("waves won't fit in RAM!");
  84.  
  85.     for(i=0; i<4; i++)
  86.     { dynamix[i] = 0; }    /* no dynamic I/O blocks allocated 
  87.                      * for any channel thus far */
  88.     return(0);
  89. }
  90.  
  91. FinishAudio()
  92. {
  93.     LONG i;
  94.     struct ExtIOB *iob;
  95.        for(i=0; i<AUDBUFFERS; i++)
  96.     {    if(inuse[i] == YES)
  97.         {    /* make sure all global blocks are done */
  98.             WaitIO(&audbuffer[i]);
  99.         }
  100.        }
  101. #ifdef DEBUG
  102.     printf("All global I/O blocks are done\n");
  103.     printf("channels 0,1,2,3 have %ld,%ld,%ld,%ld blocks in play\n",
  104.         dynamix[0], dynamix[1], dynamix[2], dynamix[3]);
  105. #endif DEBUG
  106.     for(i=0; i<4; i++)
  107.  
  108.         {   if(dynamix[i])  /* If this channel still playing a   */
  109.                 /* dynamically allocated block, wait */
  110.                 /* for all messages to return before */
  111.                 /* the program exits.                */
  112.         {  
  113.     emptyit:   
  114.         iob = (struct ExtIOB *)GetMsg(replyPort[i]);
  115.         if(iob == 0 && dynamix[i] != 0)    /* if no message arrived... */
  116.         {  WaitPort(replyPort);  /* wait for  I/O done */
  117.            goto emptyit;     /* and empty the port */
  118.         }
  119.         FreeIOB(iob,i);
  120.         if(dynamix[i] != 0) goto emptyit;
  121.         }
  122.     }
  123.        for(i=0; i<4; i++)   FreeChannel(i);
  124.     finishup("Done!\n");
  125.     return(0);
  126. }
  127.  
  128. finishup(string)
  129. char *string;
  130. {
  131.           int i;
  132.           
  133.     if(device) CloseDevice(&openIOB);
  134.     printf("closed the device\n");
  135.  
  136.           for(i=0; i<4; i++)
  137.     {          if(chipaudio[i]) FreeMem(chipaudio[i],WAVES_TOTAL);
  138.           if(replyPort[i]) 
  139.             DeletePort(replyPort[i]);
  140.     }
  141.     if(controlPort) DeletePort(controlPort);
  142.     printf("%ls\n",string);
  143.        exit(0);
  144.     return(0);
  145. }
  146.  
  147. int
  148. ControlChannel(channel, command)
  149.     WORD channel;
  150.     WORD command;
  151. {
  152.     LONG rtn;
  153.     struct ExtIOB *iob, controlIOB;
  154.  
  155.     iob = &controlIOB;
  156.     iob->ioa_Request.io_Device    = device;
  157.     iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
  158.  
  159.     InitBlock(iob,channel);    /* init it for CMD_WRITE, then change */
  160.  
  161.     iob->ioa_Request.io_Command = command;
  162.     iob->ioa_Request.io_Flags   = IOF_QUICK;
  163.  
  164.     BeginIO(iob);
  165.     WaitIO(iob);
  166.     rtn = ((LONG)(iob->ioa_Request.io_Error));
  167.     return(rtn);
  168. }
  169.  
  170. struct ExtIOB *
  171. GetIOB(ch)
  172.     LONG ch;
  173. {
  174.     WORD i,use_reply;
  175.     struct ExtIOB *iob;  /* in case we need to allocate one */
  176.     ReEmployIOB();     /* find already used ones and free them */
  177.                   /* so that when we do a get... */
  178.     if(ch == -1)  use_reply = 0;  /* which reply port to use */
  179.     else          use_reply = ch;
  180.  
  181.     for(i=0; i<AUDBUFFERS; i++)
  182.     {   if(inuse[i] == NO)
  183.         {   inuse[i] = YES;
  184.         audbuffer[i].ioa_Request.io_Device    = device;
  185.         audbuffer[i].ioa_Request.io_Message.mn_ReplyPort = 
  186.                         replyPort[use_reply];
  187.         audbuffer[i].ioa_Request.io_Message.mn_Length = i;
  188.         audbuffer[i].ioa_Request.io_Message.mn_Node.ln_Name = 
  189.                         globalname;
  190. #ifdef DEBUG
  191.         printf("Using a global iob\n");
  192. #endif DEBUG
  193.         return(&audbuffer[i]);
  194.         }
  195.     }
  196.     /* if all globals are in use, have to allocate one */
  197.     iob = (struct ExtIOB *)AllocMem(sizeof(struct ExtIOB),
  198.                             MEMF_CLEAR);
  199.     if(iob == 0) return(0);    /* out of memory */
  200.     else
  201.     {    iob->ioa_Request.io_Device = device;
  202.         iob->ioa_Request.io_Message.mn_ReplyPort = 
  203.                     replyPort[use_reply];
  204.         iob->ioa_Request.io_Message.mn_Node.ln_Name = 
  205.                     dynamicname;
  206.         iob->ioa_Request.io_Message.mn_Length = dynamix[use_reply];
  207.         dynamix[use_reply] += 1; /* add one to number allocated
  208.                       * for a specific channel */
  209. #ifdef DEBUG
  210.         printf("Allocated a new dynamic iob\n");
  211. #endif DEBUG
  212.         return(iob);
  213.     }
  214. return(0);
  215. }
  216.  
  217. /* ReEmployIOB - look at all of the reply ports and if any IOBs
  218.  *          hanging around with nothing to do, free them.
  219.  */
  220. ReEmployIOB()
  221. {
  222.     LONG i;
  223.     struct MsgPort *mp;
  224.     struct ExtIOB *iob;
  225.  
  226.     for(i=0; i<4; i++)    /* remove all iob's from all ports */
  227.     {    mp = replyPort[i];
  228.         while( (iob = (struct ExtIOB *)GetMsg(mp)) != 0)
  229.         { 
  230. #ifdef DEBUG
  231.           printf("type of iob freed is: %ls\n",
  232.               iob->ioa_Request.io_Message.mn_Node.ln_Name);
  233.           printf("its identifier value is: %ld\n",
  234.               iob->ioa_Request.io_Message.mn_Length);
  235. #endif DEBUG
  236.           FreeIOB(iob, i);
  237.         }
  238.     }
  239.     return(0);
  240. }
  241.  
  242. /* Free a global or an allocated IOB */
  243. int
  244. FreeIOB(iob, ch)
  245.     struct ExtIOB *iob;
  246.     LONG ch;    /* which channel was it attached to? */
  247. {
  248.     WORD i;
  249.  
  250.     if(iob->ioa_Request.io_Message.mn_Node.ln_Name == dynamicname)
  251.     {    FreeMem(iob, sizeof(struct ExtIOB));
  252.         if(dynamix[ch]) dynamix[ch] -= 1; /* subtract one if nonzero */
  253.         return(0L);
  254.     }
  255.     else if(iob->ioa_Request.io_Message.mn_Node.ln_Name == globalname)
  256.     {    i = iob->ioa_Request.io_Message.mn_Length;
  257. #ifdef DEBUG
  258.         printf("Freeing global buffer numbered %ld\n",i);
  259. #endif DEBUG    
  260.         if(i < AUDBUFFERS)
  261.         {    inuse[i] = NO;    /* frees this one for reuse */
  262.         }
  263.         return(0L);
  264.     }
  265.     /* if get here, the names don't match... something is wrong.*/
  266.     else {    printf("FreeIOB: names don't match...unknown error\n");
  267.     return(-1);    /* unknown source of IOB fed to routine. */
  268.     }
  269. return(0);
  270. }
  271.  
  272. /* Initialize an audio I/O block for default CMD_WRITE operation. */
  273. int
  274. InitBlock(iob, channel)
  275.       struct ExtIOB *iob;
  276.     WORD channel;
  277. {
  278.     /* Device and ReplyPort fields have been initialized by GetIOB */
  279.     iob->ioa_Request.io_Unit = unit[channel];
  280.  
  281.     /* Allocation key */
  282.     iob->ioa_AllocKey = key[channel];
  283.  
  284.     /* Where is the waveform?  Just be sure is in MEMF_CHIP!!! */
  285.     /* USER initializes datalength[ch] before calling this;    */
  286.     /* for sampled sound command write operation.              */
  287.     iob->ioa_Data     = chipaudio[channel];
  288.     iob->ioa_Length = datalength[channel];
  289.  
  290.     /* Another routine, must initialize:
  291.  
  292.         period        ioa_Period
  293.         volume        ioa_Volume
  294.         cycles        ioa_Cycles
  295.         message        ioa_WriteMessage
  296.     */
  297.     /* Default command type is CMD_WRITE */
  298.     iob->ioa_Request.io_Command = CMD_WRITE;
  299.  
  300.     /* If IOF_QUICK is zeroed, this would affect the
  301.      * period and volume.  If a CMD_WRITE, it queues if
  302.      * another note is already playing.  We queue CMD_WRITES.
  303.      */
  304.     iob->ioa_Request.io_Flags = ADIOF_PERVOL;
  305.     return(0);
  306. }
  307.  
  308. /* To request "any" stereo pair, use pair = -1;
  309.  * To request a specific stereo pair, use pair = {0, 1, 2 or 3}
  310.  * corresponding to channels 0 and 1, 0 and 2, 1 and 2 or 1 and 3
  311.  * respectively.
  312.  */
  313. int
  314. GetStereoPair(pair)
  315.     LONG pair;
  316. {
  317.     int error, value;
  318.     struct ExtIOB *iob, controlIOB;
  319.  
  320.     iob = &controlIOB;
  321.     iob->ioa_Request.io_Device    = device;
  322.     iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
  323.  
  324.     InitBlock(iob,0);    /* init it for CMD_WRITE, then change */
  325.  
  326.     /* set precedence of the request for a channel */
  327.     iob->ioa_Request.io_Message.mn_Node.ln_Pri = 20;
  328.  
  329.     /* Type of command is ALLOCATE */
  330.     iob->ioa_Request.io_Command = ADCMD_ALLOCATE;
  331.     if(pair == -1)
  332.     {    /* Point to the allocation map */ 
  333.         iob->ioa_Data = (UBYTE *)stereostuff;
  334.         
  335.         /* It contains 4 entries */
  336.         iob->ioa_Length = 4;
  337.     }
  338.     else if(pair >=0 && pair <= 3)
  339.     {    iob->ioa_Data = (UBYTE *)(&stereostuff[pair]);
  340.         iob->ioa_Length = 1;
  341.     }
  342.     else    /* chose a bad channel pair; cannot allocate it */
  343.     {    
  344.         return(-1);
  345.     }
  346.     /* Don't wait for allocation, channels
  347.      * should be available!  If we don't set
  348.      * ADIOF_NOWAIT, the task will idle waiting
  349.      * for a chance to allocate the channel, 
  350.      * looking again each time another task
  351.      * allocates or frees a channel.         
  352.      */
  353.     iob->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
  354.  
  355.     BeginIO(iob); 
  356.  
  357.     error = WaitIO(iob);  /* returns nonzero if error */
  358.     if(!(iob->ioa_Request.io_Flags & IOF_QUICK))
  359.     {    /* if flag not set, then the message
  360.          * was appended to the reply port 
  361.          * (was not quick I/O after all)  */
  362.         GetMsg(iob->ioa_Request.io_Message.mn_ReplyPort);
  363.     }
  364.     if(error)
  365.     {    return(-1);
  366.     }
  367.     /* Save the values... freeing the IOB on exit */
  368.     gotunit   = (iob->ioa_Request.io_Unit);
  369.     gotkey      = (iob->ioa_AllocKey);
  370.         
  371.     switch((LONG)(iob->ioa_Request.io_Unit))
  372.     {    case  3:    value = 0;    break;
  373.         case  5:    value = 1;    break;
  374.         case 10:    value = 2;    break;
  375.         case 12:    value = 3;    break;
  376.         default:    value = -1;    break;
  377.     }
  378.     return(value);
  379. }
  380.  
  381. /* To request "any" channel, use ch = -1;
  382.  * To request a specific channel, use ch = {0, 1, 2 or 3};
  383.  */
  384. int
  385. GetChannel(ch)
  386.     LONG ch;
  387. {
  388.     int error, value;
  389.     struct ExtIOB *iob, controlIOB;
  390.  
  391.     iob = &controlIOB;
  392.     iob->ioa_Request.io_Device    = device;
  393.     iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
  394.  
  395.     InitBlock(iob,0);    /* init it for CMD_WRITE, then change */
  396.  
  397.     iob->ioa_Request.io_Message.mn_Node.ln_Pri = 20;
  398.     iob->ioa_Request.io_Command = ADCMD_ALLOCATE;
  399.  
  400.     if(ch == -1)
  401.     {    iob->ioa_Data = (UBYTE *)anychan;
  402.         iob->ioa_Length = 4;
  403.     }
  404.     else if(ch >=0 && ch <= 3)
  405.     {    iob->ioa_Data = (UBYTE *)(&anychan[ch]);
  406.         iob->ioa_Length = 1;
  407.     }
  408.     else    /* chose a bad channel number; cannot allocate it */
  409.     {    return(-1);
  410.     }
  411.     iob->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
  412.     BeginIO(iob); 
  413.     error = WaitIO(iob);  /* returns nonzero if error */
  414.     if(!(iob->ioa_Request.io_Flags & IOF_QUICK))
  415.     {    GetMsg(iob->ioa_Request.io_Message.mn_ReplyPort);
  416.     }
  417.     if(error)
  418.     {    return(-1);
  419.     }
  420.     gotunit      = (iob->ioa_Request.io_Unit);
  421.     gotkey    = (iob->ioa_AllocKey);
  422.     switch((LONG)(iob->ioa_Request.io_Unit))
  423.     {    case  1:    value = 0;    break;
  424.         case  2:    value = 1;    break;
  425.         case  4:    value = 2;    break;
  426.         case  8:    value = 3;    break;
  427.         default:    value = -1;    break;
  428.     }
  429.     return(value);
  430. }
  431.  
  432. int 
  433. FreeChannel(ch)
  434.     LONG ch;
  435. {
  436.     int error;
  437.     struct ExtIOB *iob, controlIOB;
  438.  
  439.     iob = &controlIOB;
  440.     iob->ioa_Request.io_Device    = device;
  441.     iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
  442.  
  443.     InitBlock(iob,ch);    /* init it for CMD_WRITE, then change       */
  444.                 /* (pick up unit and key value for channel) */
  445.     iob->ioa_Request.io_Command = ADCMD_FREE;
  446.     iob->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
  447.     BeginIO(iob); 
  448.     error = WaitIO(iob);  /* returns nonzero if error */
  449.  
  450.     if(!(iob->ioa_Request.io_Flags & IOF_QUICK))
  451.     {    GetMsg(iob->ioa_Request.io_Message.mn_ReplyPort);
  452.     }
  453.     if(error)
  454.     {    return(-1);
  455.     }
  456.     return(0);
  457. }
  458. /* NOTE:  FreeChannel should work as FreeStereoPair(pair) too! */
  459.  
  460. /* THE FOLLOWING ROUTINES ARE PARAPHRASED FROM A USENET and BIX
  461.  * POSTING MADE IN 1985 BY STEVEN A. BENNETT.  
  462.  */
  463. /* I have modified his routines to queue the audio commands in 
  464.  * place of starting forever-duration and canceling each note.
  465.  * Many of his original comments have been incorporated into
  466.  * the article. 
  467.  */
  468.  
  469. /* PlayNote(...) */
  470. /* Starts a sound on the channel with specified period and volume. */
  471. /* This nice little routine takes a note and plays it on the given
  472.  * voice.  The note is basically an integer from
  473.  * 0 to 11 (c to b) plus 12 per octave above the first and lowest. 
  474.  *
  475.  * The waveform to use is determined by adding an index (woffsets[]) 
  476.  * dependant on the octave.
  477.  *
  478.  * The length of the waveform (in wlen[]) is likewise dependant on
  479.  * the octave.  Note that octaves start with zero, not one.
  480.  */
  481. int 
  482. PlayNote(channel, note, wf, vol, duration, priority, message)
  483.    char *wf;    /* waveform to use */
  484.    LONG vol, channel, duration, note;    /* specific note number */
  485.    LONG priority;
  486.    struct Message *message;
  487.    {
  488.    LONG per, len, oct;    /* period, length of waveform, which octave */
  489.    char *wavepointer;    /* where to find start of waveform */
  490.    struct ExtIOB *iob;
  491.    int frequency;
  492.    iob = GetIOB(channel);
  493.  
  494.    if(iob != 0)
  495.    {
  496.     InitBlock(iob, channel);    /* set up for CMD_WRITE */
  497.    
  498.     oct = note / 12;
  499.     wavepointer = wf + woffsets[oct];
  500.     len = wlen[oct];
  501.     per = perval[note % 12];
  502.  
  503.        /* Set the parameters */
  504.        iob->ioa_Data = (UBYTE *)wavepointer;
  505.        iob->ioa_Length = len;
  506.        iob->ioa_Period = per;
  507.        iob->ioa_Volume = vol;
  508.  
  509. /* PlayNote (continued) */
  510.  
  511.     /* Look at the frequency that it is to play by backwards calc. */
  512.     frequency = 3579545 / (len * per);
  513.  
  514.     /* Calculate cycles from duration in 1000ths of a second */
  515.     /* Multiply all-in-one to maintain max precision possible */
  516.     /* (all integer arithmetic.) */
  517.  
  518.     iob->ioa_Cycles = ((LONG)(frequency * duration)/1000);
  519.        BeginIO(iob);
  520.     return(0);        /* all went ok */
  521.    }
  522.    else
  523.    {    return(-1);        /* couldnt get IOB */
  524.    }
  525. return(0);
  526. }
  527.   
  528. /* SetPV(channel, per, vol)
  529.  *   int channel, per, vol;
  530.  */
  531. int 
  532. SetPV(channel, per, vol)
  533.    int channel, per, vol;
  534.    {
  535.    int error;
  536.    struct ExtIOB *iob, controlIOB;
  537.  
  538.    iob = &controlIOB;
  539.    iob->ioa_Request.io_Device    = device;
  540.    iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
  541.  
  542.    InitBlock(iob, channel);    /* set up for CMD_WRITE */
  543.    
  544.    iob->ioa_Period = per;
  545.    iob->ioa_Volume = vol;
  546.    iob->ioa_Request.io_Command = ADCMD_PERVOL;
  547.    iob->ioa_Request.io_Flags   = IOF_QUICK | ADIOF_PERVOL;
  548.    BeginIO(iob);    /* This one will be synchronous; affects whatever
  549.              * is playing on this channel at this time.
  550.              */
  551.    error = WaitIO(iob);    /* OK to wait, since it will return */
  552.    return(error);        /* copy of io_Error field; should be 0 */
  553. }
  554.  
  555. /* SetWaves(w1, w2, w3): create first sawtooth, triangle and square wave */
  556.  
  557. SetWaves(w1, w2, w3)
  558.    UBYTE *w1, *w2, *w3;
  559. {
  560.    int i, increment, value, sqvalue;
  561.    value = 0; increment = 2;
  562.    sqvalue = 127;
  563.  
  564.    for (i = 0; i < BIG_WAVE; ++i)
  565.    {
  566.     w1[i] = i;    /* do the sawtooth */
  567.  
  568.     if(i > 62 && i < 180) increment = -2;
  569.     else
  570.     if(i >= 180) increment = 2;
  571.  
  572.     w2[i] = value;  value += increment;  /* triangle wave */
  573.  
  574.     if(i > 126) sqvalue = -127;
  575.  
  576.     w3[i] = sqvalue;
  577.    }
  578. return(0);
  579. }
  580.   
  581. /* ExpandWave(wfp) - replicate waves in decreasing sample sizes
  582.  *   BYTE *wfp;
  583.  */
  584.  
  585. ExpandWave(wfp)
  586.    BYTE *wfp;
  587.    {
  588.    int i, j, rate;
  589.    BYTE *tptr;
  590.  
  591.    rate = 1;
  592.    tptr = wfp + BIG_WAVE;
  593.    for (i = 0; i < NBR_WAVES - 1; ++i)
  594.       {
  595.       rate *= 2;
  596.       for (j = 0; j < BIG_WAVE; j += rate)
  597.          *tptr++ = wfp[j];
  598.       }
  599.    return(0);
  600.    }
  601.   
  602. /* MakeWaves()
  603.  *
  604.  *   Just makes a sawtooth, triangle and square wave in chip mem 
  605.  * and expands them.
  606.  */
  607. int 
  608. MakeWaves()
  609. {
  610.    /* allocate the memory for the waveforms.
  611.     */
  612.    w1 = (UBYTE *)AllocMem(WAVES_TOTAL, MEMF_CHIP);
  613.    w2 = (UBYTE *)AllocMem(WAVES_TOTAL, MEMF_CHIP);
  614.    w3 = (UBYTE *)AllocMem(WAVES_TOTAL, MEMF_CHIP);
  615.  
  616.    if (w1 == NULL || w2 == NULL || w3 == NULL)
  617.     return(-1);    /* ran out of memory! */
  618.  
  619.    /* get and expand the waveforms    */
  620.  
  621.    SetWaves(w1, w2, w3);
  622.    ExpandWave(w1);    chipaudio[0]=w1;
  623.    ExpandWave(w2);    chipaudio[1]=w2;
  624.    ExpandWave(w3);    chipaudio[2]=w3;
  625.    return(0);
  626. }
  627.